/*

 tanilaeditor

 Version: 0.1
 Author: Alexander Kaupp aka tanila ( tanila at tanila dot de )

Software License Agreement (BSD License)
Copyright (c) 2009, Alexander Kaupp
All rights reserved.

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials   	 provided with the distribution.
    * Neither the name of Alexander Kaupp nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written 	  permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


 requires: yui, oop, event, dom, node 

 Notes:
 - this is a really basic and early version
 - feel free to contact me if you make changes or if you have a feature request or any ideas to make the editor better
 - thanks to all the yahoo developers. they did a really great job :)	

*/

YUI.add('tanilaeditor', function(Y) {

/**
 * n: the textareaNode
 * cfg the config obj
*/
var tanilaeditor = (function (n,cfg) {
		 var defaultCfg = {
				replaceClass:'isTextareaExt',	// the css-class for textareas which should be replaced by the editor
				cssURL:'',	// the css for the editor iframe. If no css is given the page css is loaded into the iframe
				editorBodyCSSClass:'te_editor',	// the css-class for the editor body
				btn: [
					 ["doShowSrc","Quelltext"],
//					 ["doSave", "Speichern"],
					 ["undo","R&uuml;ckg&auml;ngig machen"] ,
					 ["redo","Wiederholen"],
					 ["bold","Fett"],
					 ["italic","Kursiv"],
					 ["underline","Unterstrichen"],
//					 ["doTextColor","Textfarbe"],
//					 ["doTextBGColor","Texthintergrundfarbe"],
					 ["strikethrough","Druchgestrichen"],
					 ["superscript","Hochgestellt"],
					 ["subscript","Tiefgestellt"],
//					 ["createlink","Link hinzuf&uuml;gen oder entfernen"],
//					 ["unlinklink","Link hinzuf&uuml;gen oder entfernen"],
					 ["insertorderedlist","Nummerierte Liste"],
					 ["insertunorderedlist","Aufz&auml;hlungsliste"],
					 ["outdent","Einr&uuml;ckung verringern"],
					 ["indent", "Einr&uuml;ckung vergr&ouml;&szlig;ern"],
					 ["justifyleft","Linksb&uuml;ndig"],
					 ["justifycenter","Zentriert ausrichten"],
					 ["justifyright","Rechtsb&uuml;ndig"],
					 ["justifyfull","Blocksatz"]
//					 ["doSpellcheck","Rechtschreibpr&uuml;fung"],
//					 ["test","test"]
					]},
		wysiwig = true,
		pnlBtns = [],

		executeCMD = function(cmd){
		if (cmd ) {
			try {	// try to exec the command by iframe command
				if (!cExec.execCommand(cmd,false,null) )
					try { eval( cmd+'()' ); } catch(e) { alert(e); } // try to exec as local function
				} catch(e) {
					// opera fires an exception if execCommand fails
					try { eval( cmd+'()' ); } catch(e) { alert(e); }
				}
			focus();
			toggleBtnState(cmd,1);
		}
	},

	pnlClk = function(e) {
	executeCMD(e.target.cmd);
	e.halt();
	};

	function setBtnState (btn,on) {
		btn = pnlBtns[btn];
		if (btn) {
			if (on) {
				btn.addClass('isactive');
				}
			else {
				btn.removeClass('isactive');
			}
		}
	}

	function toggleBtnState(btn) {
		btn = pnlBtns[btn];
		if (btn) {
			btn.toggleClass('isactive');
		}
	}

	function setHTML() {
		if (wysiwig)
			cExec.body.innerHTML = text.get('value');
		else
			text.set('value', cExec.body.innerHTML);
	}

	function toggleWysiwig() {
		if (wysiwig) {
			editor.setStyle('display','none');
			text.setStyle('display','block');
		} else {
			text.setStyle('display','none');
			editor.setStyle('display','block');
		}
		wysiwig = !wysiwig;
		setHTML();
	}

	function createPanel() {
		var j = cfg.btn.length-1;
		for (var i = 0; i<= j; i +=1) {
			pnlBtns[cfg.btn[i][0]] = Y.Node.create('<a href="#" id="te_'+cfg.btn[i][0]+'" title="'+cfg.btn[i][1]+'"></a>');
			pnlBtns[cfg.btn[i][0]].cmd =cfg.btn[i][0];
			pnl.appendChild(pnlBtns[cfg.btn[i][0]]);
		}
		pnl.on('click', pnlClk );
		parent.insertBefore( pnl , text );
	}

	function createEditor() {
		r = text.get('region');
		// add all textarea css classes to the editor iframe
		editor.addClass( text.getAttribute('class') );
		text.removeClass('isRequired');
		text.setStyle('display','none');
		// loopthrough textarea focus();
		text.on('focus', function(e) { focus(); });

		// sizing the iframe
		editor.setStyle('width', r.width+'px');
		editor.setStyle('height', r.height+'px');
		parent.insertBefore(editor , text );
	}

	function setEditorCSS(cssURL) {
		// if no cssURL use the page css
		if (!cssURL) css = document.styleSheets[0].href;
		if(document.all)
		// I dont know why IE throws an unknown error here... I love IE :O
			try {
			document.frames[editorId].document.body.className = cfg.editorBodyCSSClass;
			cExec.createStyleSheet(css);
			} catch (e) {}
		else {
			s = cExec.createElement("link");
			s.rel = "stylesheet";
			s.type ="text/css";
			s.href = css;
			cExec.getElementsByTagName("head")[0].appendChild(s);
			cExec.body.setAttribute('class', cfg.editorBodyCSSClass);
		}
	}

	function enableEditor(){
		access = document.getElementById(editorId);
		cExec = access.contentWindow.document;
		cExec.designMode = "on";
		// copy textarea HTML to iframe
		setEditorCSS();
		try {	// IE6 throws an object error!
			setHTML();
		} catch(e) {}
		editor.get('contentWindow.document').on('keyup', pnlFeedback );
		editor.get('contentWindow.document').on('mouseup', pnlFeedback );
	}

	function focus() {
	if (!access) { access = document.getElementById(editorId) }
	if (wysiwig) {
		access.contentWindow.focus();
	} 	else {
		text.focus();
		}
	}

	function getHTML(){
		return cExec.body.innerHTML
	}

	// non iFrame Functions:
	function doShowSrc() {
		toggleWysiwig();
	}

	// returns the parent node of the current selectin in the iframe
	function getSelectedNode() {
		var parentNode = 0,
			selection =0,
			range =0;
		/* IE selections */
		if (access.contentWindow.document.selection)  {
			selection = access.contentWindow.document.selection;
			range = selection.createRange();
			try {
				parentNode = range.parentElement();
			} catch (e) { return }
		}
		/* Mozilla selections */
		else 	{
			try {
				selection =  access.contentWindow.getSelection();
			} catch (e) { return }
			range = selection.getRangeAt(0);
			parentNode = range.commonAncestorContainer;
		}
		return parentNode;
	}

	function pnlFeedback(){
		// unstate all btns
		for (i in pnlBtns) { setBtnState(i,0); };

		node = getSelectedNode();
		// get the topmost node of of type text
		while (node.nodeType == 3) { node = node.parentNode; 	}

		// set buton styles
		while (node.nodeName.toLowerCase()  != 'body') 	{
			style = node.getAttribute('style');
			align = node.getAttribute('align');
			// typecasting needed 4 ie
			if (typeof(style) == 'string') {
				if (style.match(/bold/i)) setBtnState("bold", 1);
				if (style.match(/italic/i)) setBtnState("italic", 1);
				if (style.match(/underline/i)) setBtnState("underline", 1);
				if (style.match(/line-through/i)) setBtnState("strikethrough", 1);
			}
			// wrapping here because align can be in style or in align attribute
			aln = (style) ? style : align;
			// typecasting needed 4 ie
			if (typeof(aln) == 'string') {
				if (aln.match(/left/i)) setBtnState("justifyleft", 1);
				else if (aln.match(/right/i)) setBtnState("justifyright", 1);
				else if (aln.match(/center/i)) setBtnState("justifycenter", 1);
				else if (aln.match(/justify/i)) setBtnState("justifyfull", 1);
			}

			switch ( node.nodeName.toLowerCase() ) {
				case "a":
					setBtnState('createlink');
					break;
				case "em" || "i":
					setBtnState('italic', 1);
					break;
				case "u":
					setBtnState('underline', 1);
					break;
				case "strike":
					setBtnState('strikethrough', 1);
					break;
				case "sup":
					setBtnState('superscript', 1);
					break;
				case "sub":
					setBtnState('subscript', 1);
					break;
				case "ol":
					setBtnState('insertorderedlist', 1);
					setBtnState('insertunorderedlist', 0);
					break;
				case "strong" || "b":
					setBtnState("bold", 1);
					break;
				case "ul":
					setBtnState("insertorderedlist", 0);
					setBtnState("insertunorderedlist",1);
					break;
			} // switch
			node = node.parentNode;
		}
	};

		var text = n,
		textId = n.get('name'),
		editorId = textId+'_editor',
		parent = n.get('parentNode'),
		form = text.get('form'),
		pnl = Y.Node.create('<div class="te_panel" id="'+textId+'_panel"></div>'),
		css = '',
		access = 0,
		cExec = 0,
		editor = Y.Node.create('<iframe id="'+editorId+'" frameborder="0"></iframe>');
		  if (!cfg)  cfg =defaultCfg;
		createPanel();
		createEditor();
		// enable editor when iframe has loaded
		Y.on("load", enableEditor, editor, Y);

	// public
	return {
		replaceTextareas : function () {
			var te=Y.Node.all('.'+cfg.replaceClass);
			Y.each( te, function(v) {init(v) });
		} 
	};	// public
});

var te=Y.Node.all('.isTextareaExt');
Y.each( te, function(v) { tanilaeditor(v) });

});
